// Copyright 2021 Tencent Inc. All rights reserved.
//
// 商家转账对外API
//
// * 场景及业务流程：     商户可通过该产品实现同时向多个用户微信零钱进行转账的操作，可用于发放奖金补贴、佣金货款结算、员工报销等场景。
// [https://pay.weixin.qq.com/index.php/public/product/detail?pid=108&productType=0](https://pay.weixin.qq.com/index.php/public/product/detail?pid=108&productType=0) * 接入步骤：     * 商户在微信支付商户平台开通“批量转账到零钱”产品权限，并勾选“使用API方式发起转账”。     * 调用批量转账接口，对多个用户微信零钱发起转账。     * 调用查询批次接口，可获取到转账批次详情及当前状态。     * 调用查询明细接口，可获取到单条转账明细详情及当前状态。
//
// API version: 1.0.5

// Code generated by WechatPay APIv3 Generator based on [OpenAPI
// Generator](https://openapi-generator.tech); DO NOT EDIT.

package com.wechat.pay.java.service.transferbatch;

import static com.wechat.pay.java.core.http.UrlEncoder.urlEncode;
import static com.wechat.pay.java.core.util.GsonUtil.toJson;
import static java.util.Objects.requireNonNull;

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.cipher.PrivacyDecryptor;
import com.wechat.pay.java.core.cipher.PrivacyEncryptor;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.exception.ValidationException;
import com.wechat.pay.java.core.http.Constant;
import com.wechat.pay.java.core.http.DefaultHttpClientBuilder;
import com.wechat.pay.java.core.http.HostName;
import com.wechat.pay.java.core.http.HttpClient;
import com.wechat.pay.java.core.http.HttpHeaders;
import com.wechat.pay.java.core.http.HttpMethod;
import com.wechat.pay.java.core.http.HttpRequest;
import com.wechat.pay.java.core.http.HttpResponse;
import com.wechat.pay.java.core.http.JsonRequestBody;
import com.wechat.pay.java.core.http.MediaType;
import com.wechat.pay.java.core.http.QueryParameter;
import com.wechat.pay.java.core.http.RequestBody;
import com.wechat.pay.java.service.transferbatch.model.GetTransferBatchByNoRequest;
import com.wechat.pay.java.service.transferbatch.model.GetTransferBatchByOutNoRequest;
import com.wechat.pay.java.service.transferbatch.model.GetTransferDetailByNoRequest;
import com.wechat.pay.java.service.transferbatch.model.GetTransferDetailByOutNoRequest;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferRequest;
import com.wechat.pay.java.service.transferbatch.model.InitiateBatchTransferResponse;
import com.wechat.pay.java.service.transferbatch.model.TransferBatchEntity;
import com.wechat.pay.java.service.transferbatch.model.TransferDetailEntity;

/** TransferBatchService服务 */
public class TransferBatchService {

  private final HttpClient httpClient;
  private final HostName hostName;
  private final PrivacyEncryptor encryptor;
  private final PrivacyDecryptor decryptor;

  private TransferBatchService(
      HttpClient httpClient,
      HostName hostName,
      PrivacyEncryptor encryptor,
      PrivacyDecryptor decryptor) {
    this.httpClient = requireNonNull(httpClient);
    this.hostName = hostName;
    this.encryptor = requireNonNull(encryptor);
    this.decryptor = requireNonNull(decryptor);
  }

  /** TransferBatchService构造器 */
  public static class Builder {

    private HttpClient httpClient;
    private HostName hostName;
    private PrivacyEncryptor encryptor;
    private PrivacyDecryptor decryptor;

    public Builder config(Config config) {
      this.httpClient = new DefaultHttpClientBuilder().config(config).build();
      this.encryptor = config.createEncryptor();
      this.decryptor = config.createDecryptor();
      return this;
    }

    public Builder hostName(HostName hostName) {
      this.hostName = hostName;
      return this;
    }

    public Builder httpClient(HttpClient httpClient) {
      this.httpClient = httpClient;
      return this;
    }

    public Builder encryptor(PrivacyEncryptor encryptor) {
      this.encryptor = encryptor;
      return this;
    }

    public Builder decryptor(PrivacyDecryptor decryptor) {
      this.decryptor = decryptor;
      return this;
    }

    public TransferBatchService build() {
      return new TransferBatchService(httpClient, hostName, encryptor, decryptor);
    }
  }

  /**
   * 通过微信批次单号查询批次单
   *
   * @param request 请求参数
   * @return TransferBatchEntity
   * @throws HttpException 发送HTTP请求失败。例如构建请求参数失败、发送请求失败、I/O错误等。包含请求信息。
   * @throws ValidationException 发送HTTP请求成功，验证微信支付返回签名失败。
   * @throws ServiceException 发送HTTP请求成功，服务返回异常。例如返回状态码小于200或大于等于300。
   * @throws MalformedMessageException 服务返回成功，content-type不为application/json、解析返回体失败。
   */
  public TransferBatchEntity getTransferBatchByNo(GetTransferBatchByNoRequest request) {
    String requestPath = "https://api.mch.weixin.qq.com/v3/transfer/batches/batch-id/{batch_id}";

    GetTransferBatchByNoRequest realRequest = request;
    // 添加 path param
    requestPath = requestPath.replace("{" + "batch_id" + "}", urlEncode(realRequest.getBatchId()));

    // 添加 query param
    QueryParameter queryParameter = new QueryParameter();
    if (realRequest.getNeedQueryDetail() != null) {
      queryParameter.add(
          "need_query_detail", urlEncode(realRequest.getNeedQueryDetail().toString()));
    }
    if (realRequest.getOffset() != null) {
      queryParameter.add("offset", urlEncode(realRequest.getOffset().toString()));
    }
    if (realRequest.getLimit() != null) {
      queryParameter.add("limit", urlEncode(realRequest.getLimit().toString()));
    }
    if (realRequest.getDetailStatus() != null) {
      queryParameter.add("detail_status", urlEncode(realRequest.getDetailStatus()));
    }
    requestPath += queryParameter.getQueryStr();
    if (this.hostName != null) {
      requestPath = requestPath.replaceFirst(HostName.API.getValue(), hostName.getValue());
    }
    HttpHeaders headers = new HttpHeaders();
    headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
    headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
    HttpRequest httpRequest =
        new HttpRequest.Builder()
            .httpMethod(HttpMethod.GET)
            .url(requestPath)
            .headers(headers)
            .build();
    HttpResponse<TransferBatchEntity> httpResponse =
        httpClient.execute(httpRequest, TransferBatchEntity.class);
    return httpResponse.getServiceResponse();
  }

  /**
   * 通过商家批次单号查询批次单
   *
   * @param request 请求参数
   * @return TransferBatchEntity
   * @throws HttpException 发送HTTP请求失败。例如构建请求参数失败、发送请求失败、I/O错误等。包含请求信息。
   * @throws ValidationException 发送HTTP请求成功，验证微信支付返回签名失败。
   * @throws ServiceException 发送HTTP请求成功，服务返回异常。例如返回状态码小于200或大于等于300。
   * @throws MalformedMessageException 服务返回成功，content-type不为application/json、解析返回体失败。
   */
  public TransferBatchEntity getTransferBatchByOutNo(GetTransferBatchByOutNoRequest request) {
    String requestPath =
        "https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/{out_batch_no}";

    GetTransferBatchByOutNoRequest realRequest = request;
    // 添加 path param
    requestPath =
        requestPath.replace("{" + "out_batch_no" + "}", urlEncode(realRequest.getOutBatchNo()));

    // 添加 query param
    QueryParameter queryParameter = new QueryParameter();
    if (realRequest.getNeedQueryDetail() != null) {
      queryParameter.add(
          "need_query_detail", urlEncode(realRequest.getNeedQueryDetail().toString()));
    }
    if (realRequest.getOffset() != null) {
      queryParameter.add("offset", urlEncode(realRequest.getOffset().toString()));
    }
    if (realRequest.getLimit() != null) {
      queryParameter.add("limit", urlEncode(realRequest.getLimit().toString()));
    }
    if (realRequest.getDetailStatus() != null) {
      queryParameter.add("detail_status", urlEncode(realRequest.getDetailStatus()));
    }
    requestPath += queryParameter.getQueryStr();
    if (this.hostName != null) {
      requestPath = requestPath.replaceFirst(HostName.API.getValue(), hostName.getValue());
    }
    HttpHeaders headers = new HttpHeaders();
    headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
    headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
    HttpRequest httpRequest =
        new HttpRequest.Builder()
            .httpMethod(HttpMethod.GET)
            .url(requestPath)
            .headers(headers)
            .build();
    HttpResponse<TransferBatchEntity> httpResponse =
        httpClient.execute(httpRequest, TransferBatchEntity.class);
    return httpResponse.getServiceResponse();
  }

  /**
   * 发起商家转账
   *
   * @param request 请求参数
   * @return InitiateBatchTransferResponse
   * @throws HttpException 发送HTTP请求失败。例如构建请求参数失败、发送请求失败、I/O错误等。包含请求信息。
   * @throws ValidationException 发送HTTP请求成功，验证微信支付返回签名失败。
   * @throws ServiceException 发送HTTP请求成功，服务返回异常。例如返回状态码小于200或大于等于300。
   * @throws MalformedMessageException 服务返回成功，content-type不为application/json、解析返回体失败。
   */
  public InitiateBatchTransferResponse initiateBatchTransfer(InitiateBatchTransferRequest request) {
    String requestPath = "https://api.mch.weixin.qq.com/v3/transfer/batches";
    // 加密敏感信息
    InitiateBatchTransferRequest realRequest = request.cloneWithCipher(encryptor::encrypt);
    if (this.hostName != null) {
      requestPath = requestPath.replaceFirst(HostName.API.getValue(), hostName.getValue());
    }
    HttpHeaders headers = new HttpHeaders();
    headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
    headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
    headers.addHeader(Constant.WECHAT_PAY_SERIAL, encryptor.getWechatpaySerial());
    HttpRequest httpRequest =
        new HttpRequest.Builder()
            .httpMethod(HttpMethod.POST)
            .url(requestPath)
            .headers(headers)
            .body(createRequestBody(realRequest))
            .build();
    HttpResponse<InitiateBatchTransferResponse> httpResponse =
        httpClient.execute(httpRequest, InitiateBatchTransferResponse.class);
    return httpResponse.getServiceResponse();
  }

  /**
   * 通过微信明细单号查询明细单
   *
   * @param request 请求参数
   * @return TransferDetailEntity
   * @throws HttpException 发送HTTP请求失败。例如构建请求参数失败、发送请求失败、I/O错误等。包含请求信息。
   * @throws ValidationException 发送HTTP请求成功，验证微信支付返回签名失败。
   * @throws ServiceException 发送HTTP请求成功，服务返回异常。例如返回状态码小于200或大于等于300。
   * @throws MalformedMessageException 服务返回成功，content-type不为application/json、解析返回体失败。
   */
  public TransferDetailEntity getTransferDetailByNo(GetTransferDetailByNoRequest request) {
    String requestPath =
        "https://api.mch.weixin.qq.com/v3/transfer/batches/batch-id/{batch_id}/details/detail-id/{detail_id}";

    GetTransferDetailByNoRequest realRequest = request;
    // 添加 path param
    requestPath = requestPath.replace("{" + "batch_id" + "}", urlEncode(realRequest.getBatchId()));

    requestPath =
        requestPath.replace("{" + "detail_id" + "}", urlEncode(realRequest.getDetailId()));

    if (this.hostName != null) {
      requestPath = requestPath.replaceFirst(HostName.API.getValue(), hostName.getValue());
    }
    HttpHeaders headers = new HttpHeaders();
    headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
    headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
    HttpRequest httpRequest =
        new HttpRequest.Builder()
            .httpMethod(HttpMethod.GET)
            .url(requestPath)
            .headers(headers)
            .build();
    HttpResponse<TransferDetailEntity> httpResponse =
        httpClient.execute(httpRequest, TransferDetailEntity.class);
    return httpResponse.getServiceResponse().cloneWithCipher(decryptor::decrypt);
  }

  /**
   * 通过商家明细单号查询明细单
   *
   * @param request 请求参数
   * @return TransferDetailEntity
   * @throws HttpException 发送HTTP请求失败。例如构建请求参数失败、发送请求失败、I/O错误等。包含请求信息。
   * @throws ValidationException 发送HTTP请求成功，验证微信支付返回签名失败。
   * @throws ServiceException 发送HTTP请求成功，服务返回异常。例如返回状态码小于200或大于等于300。
   * @throws MalformedMessageException 服务返回成功，content-type不为application/json、解析返回体失败。
   */
  public TransferDetailEntity getTransferDetailByOutNo(GetTransferDetailByOutNoRequest request) {
    String requestPath =
        "https://api.mch.weixin.qq.com/v3/transfer/batches/out-batch-no/{out_batch_no}/details/out-detail-no/{out_detail_no}";

    GetTransferDetailByOutNoRequest realRequest = request;
    // 添加 path param
    requestPath =
        requestPath.replace("{" + "out_detail_no" + "}", urlEncode(realRequest.getOutDetailNo()));

    requestPath =
        requestPath.replace("{" + "out_batch_no" + "}", urlEncode(realRequest.getOutBatchNo()));

    if (this.hostName != null) {
      requestPath = requestPath.replaceFirst(HostName.API.getValue(), hostName.getValue());
    }
    HttpHeaders headers = new HttpHeaders();
    headers.addHeader(Constant.ACCEPT, MediaType.APPLICATION_JSON.getValue());
    headers.addHeader(Constant.CONTENT_TYPE, MediaType.APPLICATION_JSON.getValue());
    HttpRequest httpRequest =
        new HttpRequest.Builder()
            .httpMethod(HttpMethod.GET)
            .url(requestPath)
            .headers(headers)
            .build();
    HttpResponse<TransferDetailEntity> httpResponse =
        httpClient.execute(httpRequest, TransferDetailEntity.class);
    return httpResponse.getServiceResponse().cloneWithCipher(decryptor::decrypt);
  }

  private RequestBody createRequestBody(Object request) {
    return new JsonRequestBody.Builder().body(toJson(request)).build();
  }
}
